﻿namespace CtrlTest;

[DefaultEvent("Click")]
public class IFButton : Control
{
    #region 构造方法
    /// <summary>
    /// 构造方法
    /// </summary>
    public IFButton()
    {
        /// <summary>
        /// 如果为 true，则控件忽略窗口消息 WM_ERASEBKGND 以减少闪烁。
        /// 仅当将 UserPaint 位设置为 true 时，才应用此样式。
        /// </summary>
        this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

        /// <summary>
        /// 如果为 true，则会由控件而不是由操作系统来绘制控件自身。 
        /// 如果 false，则不会引发 Paint 事件。 此样式仅适用于从
        /// Control 派生的类。
        /// </summary>
        this.SetStyle(ControlStyles.UserPaint, true);

        /// <summary>
        /// 如果为 true，则在缓冲区中进行绘制，并且完成后将结果输出到屏幕。
        /// 双缓冲可以防止因重绘控件而引起的闪烁。 如果将 DoubleBuffer 设
        /// 置为 true，则还应将 UserPaint 和 AllPaintingInWmPaint 
        /// 设置为 true。
        /// </summary>
        this.SetStyle(ControlStyles.DoubleBuffer, true);

        /// <summary>
        /// 如果为 true，则控件会在调整大小时进行重绘。
        /// </summary>
        this.SetStyle(ControlStyles.ResizeRedraw, true);

        /// <summary> 
        /// 如果为 true，则控件可以接收焦点。
        /// </summary>
        this.SetStyle(ControlStyles.Selectable, true);

        /// <summary> 
        /// SupportsTransparentBackColor
        ///     如果为 true，控件接受 alpha 组件数小于 255 个的 BackColor 来模拟透明度，
        ///     仅当将 UserPaint 位设置为 true 且父控件从 Control 派生时，
        ///     才会模拟透明度。
        /// Opaque
        ///     如果为 true，则控件会绘制为不透明，且不绘制背景。
        /// </summary>
        this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);// | ControlStyles.Opaque,

        this.Size = new Size(75, 23);
        this.BackColor = Color.FromArgb(0, 255, 255, 255);
        this.CausesValidation = true;
    }
    #endregion

    #region 按钮属性
    #region 隐藏属性
    private Color backColor;
    /// <summary>
    /// 重写背景底色(隐藏属性)
    /// </summary>
    [Browsable(false)]
    public override Color BackColor { get => backColor; set => backColor = value; }

    /// <summary>
    /// 默认填充颜色(隐藏属性)
    /// </summary>
    [Browsable(false)]
    public Color DefaultFillColor { get; set; } = Color.FromArgb(89, 202, 234, 206);

    /// <summary>
    /// 默认边框颜色(隐藏属性)
    /// </summary>
    [Browsable(false)]
    public Color DefaultBorderColor { get; set; } = Color.FromArgb(33, 147, 82);

    private bool _IsFocused = false;
    /// <summary>
    /// 是否具有焦点(隐藏属性)
    /// </summary>
    [Browsable(false)]//设置在属性窗口隐藏
    public bool IsFocused
    {
        get { return this._IsFocused; }
        set { this._IsFocused = value; Invalidate(); }
    }

    private bool _IsEnter = false;
    /// <summary>
    /// 鼠标是否进入(隐藏属性)
    /// </summary>
    [Browsable(false)]//设置在属性窗口隐藏
    public bool IsEnter
    {
        get { return this._IsEnter; }
        set { this._IsEnter = value; Invalidate(); }
    }
    #endregion

    //================================================================
    /// <summary>
    /// 按钮默认尺寸
    /// </summary>
    protected override Size DefaultSize => new Size(75, 23);

    //================================================================
    /// <summary>
    /// 重写Text属性
    /// </summary>
    public override string Text
    {
        get { return base.Text; }
        set { base.Text = value; Invalidate(); }
    }
    //================================================================
    private Color _BackFillColor = Color.FromArgb(89, 202, 234, 206);
    [Category("外观")]
    [Description("填充背景颜色")]
    [DefaultValue(typeof(Color), "89, 202, 234, 206")]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public Color BackFillColor
    {
        get { return this._BackFillColor; }
        set { this._BackFillColor = value; Invalidate(); }
    }

    //================================================================
    private Color _BorderColor = Color.FromArgb(33, 147, 82);
    [Category("外观")]
    [Description("边框颜色")]
    [DefaultValue(typeof(Color), "33, 147, 82")]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public Color BorderColor
    {
        get { return this._BorderColor; }
        set { this._BorderColor = value; Invalidate(); }
    }

    //================================================================
    private int _BorderSize = 1;
    [Category("外观")]
    [Description("边框粗细")]
    [DefaultValue(typeof(int), "1")]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public int BorderSize
    {
        get { return this._BorderSize; }
        set { this._BorderSize = value; Invalidate(); }
    }

    //================================================================
    private float _BorderRadius = 5;
    [Category("外观")]
    [Description("圆角大小")]
    [DefaultValue(typeof(float), "5")]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public float BorderRadius
    {
        get { return this._BorderRadius; }
        set
        {
            if (value <= this._BorderSize)
                throw new Exception("BorderRadius 不能 小于等于 BorderSize！");
            if (value < 0)
                throw new Exception("BorderRadius 不能 小于0！");
            this._BorderRadius = value;
            Invalidate();
        }
    }
    #endregion

    #region 按钮事件重写
    //================================================================
    #region FocusColor ====================================================
    private Color _FocusBackColor = Color.FromArgb(218, 238, 247);
    [Category("外观")]
    [Description("控件具有焦点时填充颜色")]
    [DefaultValue(typeof(Color), "218, 238, 247")]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public Color FocusBackColor
    {
        get { return this._FocusBackColor; }
        set { this._FocusBackColor = value; Invalidate(); }
    }

    //================================================================
    private Color _FocusBorderColor = Color.FromArgb(0, 120, 215);
    [Category("外观")]
    [Description("控件具有焦点时边框颜色")]
    [DefaultValue(typeof(Color), "48, 136, 164")]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public Color FocusBorderColor
    {
        get { return this._FocusBorderColor; }
        set { this._FocusBorderColor = value; Invalidate(); }
    }

    //================================================================
    /// <summary>
    /// 控件具有焦时发生的事件
    /// </summary>
    /// <param name="e">事件参数</param>
    protected override void OnGotFocus(EventArgs e)
    {
        IsFocused = true;
        if (IsEnter)
        {
            this._BorderSize = 1;
            this._BorderColor = this._MouseEnterBorderColor;
            this._BackFillColor = this._MouseEnterBackColor;
        }
        else
        {
            this._BorderSize = 2;
            this._BackFillColor = this._FocusBackColor;
            this._BorderColor = this._FocusBorderColor;
        }
        base.OnGotFocus(e);
    }
    //================================================================
    /// <summary>
    /// 控件失去焦点时发生的事件
    /// </summary>
    /// <param name="e">事件参数</param>
    //protected override void OnLostFocus(EventArgs e)
    //{
    //    base.OnLostFocus(e);
    //    Form frm = this.FindForm();
    //    if (frm.IsDisposed || frm.ActiveControl.Name.Equals(this.Name)) return;
    //    IsFocused = false;
    //    if (IsEnter)
    //    {
    //        this._BorderSize = 2;
    //        this._BorderColor = this._MouseEnterBorderColor;
    //        this._BackFillColor = this._MouseEnterBackColor;
    //    }
    //    else
    //    {
    //        this._BorderSize = 1;
    //        this._BackFillColor = this.DefaultFillColor;
    //        this._BorderColor = this.DefaultBorderColor;
    //    }
    //    Invalidate();
    //}
    #endregion

    //================================================================
    #region 鼠标进入-MouseEnter ====================================================
    private Color _MouseEnterBackColor = Color.FromArgb(30, 114, 0, 218);
    [Category("行为外观")]
    [Description("鼠标进入时填充颜色")]
    [DefaultValue(typeof(Color), "30, 114, 0, 218")]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public Color MouseEnterBackColor
    {
        get { return this._MouseEnterBackColor; }
        set { this._MouseEnterBackColor = value; Invalidate(); }
    }

    //================================================================
    private Color _MouseEnterBorderColor = Color.FromArgb(114, 0, 218);
    [Category("行为外观")]
    [Description("鼠标进入时边框颜色")]
    [DefaultValue(typeof(Color), "114, 0, 218")]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public Color MouseEnterBorderColor
    {
        get { return this._MouseEnterBorderColor; }
        set { this._MouseEnterBorderColor = value; Invalidate(); }
    }

    //================================================================
    /// <summary>
    /// 鼠标进入时发生的事件
    /// </summary>
    /// <param name="e">事件参数</param>
    protected override void OnMouseEnter(EventArgs e)
    {
        IsEnter = true;
        this._BorderColor = this._MouseEnterBorderColor;
        this._BackFillColor = this._MouseEnterBackColor;
        Invalidate();
        base.OnMouseEnter(e);
    }
    #endregion

    //================================================================
    #region 鼠标按下弹起-MouseDown and MouseUp========================================
    private Color _MouseDownBackColor = Color.FromArgb(30, 249, 50, 12);
    [Category("行为外观")]
    [Description("鼠标按下时填充颜色")]
    [DefaultValue(typeof(Color), "30, 249, 50, 12")]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public Color MouseDownBackColor
    {
        get { return this._MouseDownBackColor; }
        set { this._MouseDownBackColor = value; Invalidate(); }
    }

    //================================================================
    private Color _MouseDownBorderColor = Color.FromArgb(249, 50, 12);
    [Category("行为外观")]
    [Description("鼠标按下时边框颜色")]
    [DefaultValue(typeof(Color), "249, 50, 12")]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public Color MouseDownBorderColor
    {
        get { return this._MouseDownBorderColor; }
        set { this._MouseDownBorderColor = value; Invalidate(); }
    }

    //================================================================
    /// <summary>
    /// 鼠标按下时发生的事件
    /// </summary>
    /// <param name="e">事件参数</param>
    protected override void OnMouseDown(MouseEventArgs e)
    {
        if (e.Button != MouseButtons.Left) return;
        this.Focus();
        this._BorderColor = this._MouseDownBorderColor;
        this._BackFillColor = this._MouseDownBackColor;
        Invalidate();
        base.OnMouseDown(e);
    }
    /// <summary>
    /// 鼠标松开时发生的事件
    /// </summary>
    /// <param name="e">事件参数</param>
    protected override void OnMouseUp(MouseEventArgs e)
    {
        if (e.Button != MouseButtons.Left) return;
        if (IsFocused)
        {
            if (IsEnter)
            {
                this._BorderColor = this._MouseEnterBorderColor;
                this._BackFillColor = this._MouseEnterBackColor;

            }
            else
            {
                this._BorderSize = 2;
                this._BackFillColor = this._FocusBackColor;
                this._BorderColor = this._FocusBorderColor;
            }
        }
        else
        {
            if (IsEnter)
            {
                this._BorderColor = this._MouseEnterBorderColor;
                this._BackFillColor = this._MouseEnterBackColor;
            }
            else
            {
                this._BorderSize = 1;
                this._BackFillColor = this.DefaultFillColor;
                this._BorderColor = this.DefaultBorderColor;
            }
        }
        Invalidate();
        base.OnMouseUp(e);
    }
    #endregion

    //================================================================
    #region 鼠标离开-MouseLeave====================================================
    /// <summary>
    /// 鼠标离开时发生的事件
    /// </summary>
    /// <param name="e">事件参数</param>
    protected override void OnMouseLeave(EventArgs e)
    {
        IsEnter = false;
        if (IsFocused)
        {
            this._BorderSize = 2;
            this._BackFillColor = this._FocusBackColor;
            this._BorderColor = this._FocusBorderColor;
        }
        else
        {
            this._BorderSize = 1;
            this._BackFillColor = this.DefaultFillColor;
            this._BorderColor = this.DefaultBorderColor;
        }
        Invalidate();
        base.OnMouseLeave(e);
    }
    #endregion

    //================================================================
    #region 空格回车键响应点击事件====================================================
    /// <summary>
    /// 按键事件
    /// </summary>
    /// <param name="e">事件参数</param>
    protected override void OnKeyDown(KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Space || e.KeyCode == Keys.Enter)
        {
            this.OnClick(new MouseEventArgs(MouseButtons.Left, 1, this.Location.X, this.Location.Y, 0));
        }
        base.OnKeyDown(e);
    }

    //================================================================
    /// <summary>
    /// 按键按下事件
    /// </summary>
    /// <param name="e">事件参数</param>
    protected override void OnKeyPress(KeyPressEventArgs e)
    {
        if (e.KeyChar == (char)Keys.Space || e.KeyChar == (char)Keys.Enter)
        {
            this.OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, this.Location.X, this.Location.Y, 0));
        }
        base.OnKeyPress(e);
    }

    //================================================================
    /// <summary>
    /// 按键弹起事件
    /// </summary>
    /// <param name="e">事件参数</param>
    protected override void OnKeyUp(KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Space || e.KeyCode == Keys.Enter)
        {
            this.OnMouseUp(new MouseEventArgs(MouseButtons.Left, 1, this.Location.X, this.Location.Y, 0));
        }
        base.OnKeyUp(e);
    }
    #endregion

    //================================================================
    /// <summary>
    /// 验证事件
    /// </summary>
    /// <param name="e">事件参数</param>
    protected override void OnValidating(CancelEventArgs e)
    {
        Form frm = this.FindForm();
        if (frm.IsDisposed || frm.ActiveControl.Name.Equals(this.Name)) return;
        IsFocused = false;
        if (IsEnter)
        {
            this._BorderSize = 2;
            this._BorderColor = this._MouseEnterBorderColor;
            this._BackFillColor = this._MouseEnterBackColor;
        }
        else
        {
            this._BorderSize = 1;
            this._BackFillColor = this.DefaultFillColor;
            this._BorderColor = this.DefaultBorderColor;
        }
        Invalidate();
        base.OnValidating(e);
    }

    //================================================================
    /// <summary>
    /// 鼠标单击事件
    /// </summary>
    /// <param name="e">事件参数</param>
    protected override void OnMouseClick(MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
            base.OnMouseClick(e);
    }

    //================================================================
    #endregion

    #region 按钮重绘
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        if (!Enabled)
        {
            this.CausesValidation = false;
            this._BorderSize = 1;
            this.ForeColor = Color.DimGray;
            this._BackFillColor = Color.FromArgb(189, 204, 228);
            this._BorderColor = Color.FromArgb(189, 204, 228);
        }
        Graphics g = e.Graphics;
        if (this.Size.Width == 0 || this.Size.Height == 0)
            return;
        float haftbd = this._BorderSize / 2.0f;
        g.SmoothingMode = SmoothingMode.AntiAlias;
        //g.Clear(this.Parent.BackColor);
        if (this._BorderRadius > 0)
        {
            float rad;
            if (Math.Min(this.Size.Width - this._BorderSize, this.Size.Height - this._BorderSize) < this._BorderRadius * 2.0)
                rad = Math.Min(this.Size.Width - this._BorderSize, this.Size.Height - this._BorderSize) / 2.0f;
            else
                rad = this._BorderRadius;
            GraphicsPath gp = GetRoundedRect(0 + haftbd, 0 + haftbd, this.Size.Width - this._BorderSize, this.Size.Height - this._BorderSize, rad - haftbd);
            using (SolidBrush brush = new SolidBrush(this._BackFillColor))
            {
                g.FillPath(brush, gp);
            }
            using (Pen pen = new Pen(this._BorderColor, this._BorderSize))
            {
                g.DrawPath(pen, gp); // e是PaintEventArgs
            }
        }
        else
        {
            Rectangle rec = new Rectangle(1, 1, this.Size.Width - 1, this.Size.Height - 1);
            using (SolidBrush brush = new SolidBrush(this._BackFillColor))
            {
                g.FillRectangle(brush, rec);
            }
            using (Pen pen = new Pen(this._BorderColor, this._BorderSize))
            {
                g.DrawRectangle(pen, rec);
            }
        }
        StringFormat strfmt = new StringFormat
        {
            Alignment = StringAlignment.Center,
            LineAlignment = StringAlignment.Center
        };
        using (SolidBrush sb = new SolidBrush(this.ForeColor))
        {
            g.DrawString(this.Text, this.Font, sb, new RectangleF(0, 0, this.Size.Width, this.Size.Height), strfmt);
        }
    }

    private GraphicsPath GetRoundedRect(float x, float y, float width, float height, float radius)
    {
        GraphicsPath gp = new GraphicsPath();
        gp.StartFigure();
        //上边
        if (width > radius * 2.0) gp.AddLine(new PointF(x + radius, y), new PointF(x + width - radius - 1, y));
        //右上角
        if (radius > 0) gp.AddArc(new RectangleF(x + width - radius * 2 - 1, y, radius * 2, radius * 2), 270, 90);
        //右边
        if (height > radius * 2.0) gp.AddLine(new PointF(x + width - 1, y + radius), new PointF(x + width - 1, y + height - radius - 1));
        //右下角
        if (radius > 0) gp.AddArc(new RectangleF(x + width - radius * 2 - 1, y + height - radius * 2 - 1, radius * 2, radius * 2), 0, 90);
        //下边
        if (width > radius * 2.0) gp.AddLine(new PointF(x + width - radius - 1, y + height - 1), new PointF(x + radius, y + height - 1));
        //左下角
        if (radius > 0) gp.AddArc(new RectangleF(x, y + height - radius * 2 - 1, radius * 2, radius * 2), 90, 90);
        //左边
        if (height > radius * 2.0) gp.AddLine(new PointF(x, y + height - radius - 1), new PointF(x, y + radius));
        //左上角
        if (radius > 0) gp.AddArc(new RectangleF(x, y, radius * 2, radius * 2), 180, 90);
        gp.CloseFigure();
        return gp;
    }

    //private GraphicsPath GetRoundedRect(Rectangle rect, float radius, float bdwidth)
    //{
    //    int x = rect.X;
    //    int y = rect.Y;
    //    int width = rect.Width;
    //    int height = rect.Height;
    //    return GetRoundedRect(x, y, width, height, radius);
    //}
    #endregion
}
